iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0

單向串列
1 概念:單向串列是一種鏈結資料結構,其中每個節點包含兩部分:資料和指向下一個節點的指標而每個節點僅能透過它的指標連結到下一個節點,無法回溯。
2 重點:
1.靈活性:可在任意位置插入或刪除節點,但刪除需依賴前一個節點的指標。
2.記憶體節省:相對簡單,只需要為每個節點存儲一個指標。
3.應用場景:適合不需要經常回溯的情況,像是隊列或簡單的資料流處理。

雙向串列
1 概念:雙向串列是一種擁有雙向鏈結的資料結構,每個節點包含三部分:資料、指向前一個節點的指標、指向下一個節點的指標。
2 重點
1.雙向鏈結:每個節點有前驅和後繼兩個指標,允許向前或向後修改。
2.操作靈活性:能更方便地插入或刪除節點,特別是在雙向操作的場景中,如雙端佇列。
3.記憶體消耗:每個節點需要存儲兩個指標,記憶體需求高於單向串列。
4.應用場景:適合需要頻繁前後遍歷的應用,如雙端佇列、記憶體緩存。

小總結
1.單向串列記憶體佔用較小,適合僅需順序處理的場景。
2.雙向串列操作靈活,但記憶體需求較大,適合需要雙向操作的複雜情境。

練習實作:
(單向串列例子)

#include <iostream>
#include <string>
using namespace std;

struct Node {
    string name;
    int grade;
    Node* next;
};

// 新增節點到串列的頭部
void insertAtHead(Node*& head, string name, int grade) {
    Node* newNode = new Node{name, grade, head};
    head = newNode;
}

// 列印所有學生的姓名與成績
void display(Node* head) {
    Node* temp = head;
    while (temp != nullptr) {
        cout << "Name: " << temp->name << ", Grade: " << temp->grade << endl;
        temp = temp->next;
    }
}

// 刪除指定學生
void deleteStudent(Node*& head, string name) {
    Node* temp = head;
    Node* prev = nullptr;

    // 如果目標節點是頭節點
    if (temp != nullptr && temp->name == name) {
        head = temp->next; // 改變頭指針
        delete temp;
        return;
    }

    // 搜尋目標節點
    while (temp != nullptr && temp->name != name) {
        prev = temp;
        temp = temp->next;
    }

    // 如果未找到
    if (temp == nullptr) return;

    // 刪除節點
    prev->next = temp->next;
    delete temp;
}

int main() {
    Node* head = nullptr;
    
    // 插入學生成績
    insertAtHead(head, "Alice", 85);
    insertAtHead(head, "Bob", 90);
    insertAtHead(head, "Charlie", 75);

    // 列印學生成績
    cout << "Students List:" << endl;
    display(head);

    // 刪除學生
    deleteStudent(head, "Bob");

    cout << "\nAfter Deletion:" << endl;
    display(head);

    return 0;
}

(雙向串列例子)

#include <iostream>
#include <string>
using namespace std;

// 雙向節點結構
struct DNode {
    string name;
    int grade;
    DNode* prev;
    DNode* next;
};

// 插入節點到雙向串列的頭部
void insertAtHead(DNode*& head, string name, int grade) {
    DNode* newNode = new DNode{name, grade, nullptr, head};
    if (head != nullptr) {
        head->prev = newNode;
    }
    head = newNode;
}

// 列印從頭到尾的學生成績
void displayForward(DNode* head) {
    DNode* temp = head;
    while (temp != nullptr) {
        cout << "Name: " << temp->name << ", Grade: " << temp->grade << endl;
        temp = temp->next;
    }
}

// 列印從尾到頭的學生成績
void displayBackward(DNode* tail) {
    DNode* temp = tail;
    while (temp != nullptr) {
        cout << "Name: " << temp->name << ", Grade: " << temp->grade << endl;
        temp = temp->prev;
    }
}

// 刪除指定學生
void deleteStudent(DNode*& head, string name) {
    DNode* temp = head;

    // 搜尋目標節點
    while (temp != nullptr && temp->name != name) {
        temp = temp->next;
    }

    // 未找到
    if (temp == nullptr) return;

    // 如果是頭節點
    if (temp == head) {
        head = temp->next;
        if (head != nullptr) head->prev = nullptr;
    } else {
        temp->prev->next = temp->next;
        if (temp->next != nullptr) temp->next->prev = temp->prev;
    }

    delete temp;
}

int main() {
    DNode* head = nullptr;
    DNode* tail = nullptr;
    
    // 插入學生成績
    insertAtHead(head, "Alice", 85);
    insertAtHead(head, "Bob", 90);
    insertAtHead(head, "Charlie", 75);

    // 設定尾部指針
    tail = head;
    while (tail->next != nullptr) {
        tail = tail->next;
    }

    // 列印從頭到尾
    cout << "Students List (Forward):" << endl;
    displayForward(head);

    // 列印從尾到頭
    cout << "\nStudents List (Backward):" << endl;
    displayBackward(tail);

    // 刪除學生
    deleteStudent(head, "Bob");

    cout << "\nAfter Deletion (Forward):" << endl;
    displayForward(head);

    return 0;
}

兩個例題差別:單向串列操作較簡單但受限,雙向串列則更靈活,適合在雙向頻繁修改中。

!!以上內容是跟著第一次學C++就上手第二版第17章一起做學習的!!之後的幾天會分別有幾個小專題實作,希望能順順利利的完成~加油


上一篇
Day 22 堆疊與佇列
下一篇
Day 24 電影問卷分析系統專題製作
系列文
C++探險家30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言